pragma version 1;

struct ipv4_header {
	cluster u8 {
		field version b4;
		field ihl u4; // 32-bit words
	};

	cluster u8 {
		field dscp b6;
		field ecn b2;
	};

	field total_length u16;
	field identification u16;

	cluster u16 {
		field flags b3;
		field fragment_offset u13;
	}

	field ttl u8;
	field protocol u8;
	field header_checksum u16;

	field source_addr u32;
	field dest_addr u32;

	assert length == 4 * self.ihl;
}

struct udp_header {
	field source_port u16;
	field dest_port u16;
	field length u16;
	field checksum u16;
}

struct tcp_header {
	field source_port u16;
	field dest_port u16;
	field sequence_no u32;
	field ack_no u32;
	
	cluster u8 {
		field data_offset u4; // 32-bit words
		reserved b4;
	}
	
	field flags tcp_flags;
	
	field window_size u16;

	field checksum u16;

	field urgent_pointer u16;
	assert urgent_pointer == 0 || self.flags.urg; // is this actually checked?

	assert length == 4 * self.data_offset
}

flagmap tcp_flags u8 {
	cwr = 0;
	ece = 1;
	urg = 2;
	ack = 3;
	psh = 4;
	rst = 5;
	syn = 6;
	fin = 7;
}

struct ipv6_header {
	cluster u32 {
		field version u4;
		field traffic_class u8;
		field flow_label u20;
	}
	
	field payload_length u16;
	field next_header u8;
	field hop_limit u8;

	field source_address buf16;
	field dest_address buf16;
}

